package naito_rescue.communication.manager;

import java.util.*;
import sample.*;
import rescuecore2.messages.*;
import rescuecore2.worldmodel.*;
import rescuecore2.Constants;
import rescuecore2.config.*;
import rescuecore2.standard.components.*;
import rescuecore2.standard.entities.*;
import rescuecore2.standard.messages.*;
import rescuecore2.misc.geometry.*;

import naito_rescue.*;
import naito_rescue.agent.*;
import naito_rescue.communication.team.*;
import naito_rescue.communication.channel.*;
import naito_rescue.object.*;
import naito_rescue.message.*;
import naito_rescue.message.manager.*;

public class ChannelManager
{
	private NAITOAgent owner;
	private MyLogger   logger;
	private List<ICommunicationTeam> teams;
	private ICommunicationTeam myTeam;
	private CommunicationTeamManager teamManager;
	private Config config;
	private StandardWorldModel model;
	
	public ChannelManager(NAITOAgent owner, Config config){
		this.owner = owner;
		this.model = this.owner.getWorldModel();
		this.config = config;
		this.logger = owner.getLogger();
		
		//logger.info("ChannelManager#<Constructor>()");
		this.myTeam = null;
		teamManager = new CommunicationTeamManager(this.owner, this.config);
		this.teams = teamManager.generateTeams();
		
		//logger.trace("Process has returned to ChannelManager#<Constructor>();");
		StandardEntity me = this.owner.getMe();
		for(ICommunicationTeam team : this.teams){
			//logger.trace("Now checking team = [" + team + "]");
			List<StandardEntity> members
				 = team.getMembers();
			//logger.trace("Members = [" + members + "], I am [" + me + "].");
			if(members.contains(me)){
				//logger.debug("Found my team = [" + team + "]", "ChannelManager#<Constructor>");
				//logger.debug("My team members are = " + team.getMembers(), "ChannelManager#<Constructor>");
				this.myTeam = team;
				break;
			}
		}
		//logger.info("ChannelManager#<Constructor>() end;");
		//logger.info("myTeam = " + myTeam);
	}
	public VoiceChannel getVoiceChannel(){
		return teamManager.getVoiceChannel();
	}
	public List<AbstractChannel> getChannelToFB(){
		if(this.myTeam != null){
			return this.myTeam.getChannelToFB();
		}
		return null;
	}
	public List<AbstractChannel> getChannelToPF(){
		if(this.myTeam != null){
			return this.myTeam.getChannelToPF();
		}
		return null;
	}
	public List<AbstractChannel> getChannelToAT(){
		if(this.myTeam != null){
			return this.myTeam.getChannelToAT();
		}
		return null;
	}
	public List<AbstractChannel> getChannelsToOtherTeam(){
		if(this.myTeam != null){
			return this.myTeam.getChannelsToOtherTeam();
		}
		return null;
	}
	public AbstractChannel getMyChannel(){
		if(this.myTeam != null){
			return this.myTeam.getMyChannel();
		}
		return null;
	}
	public int getBandwidthPerAgent(){
		if(this.myTeam != null){
			return this.myTeam.getBandwidthPerAgent();
		}
		return 0;
	}
	public boolean isMyTurn(StandardEntity sender, int timestep){
		if(this.myTeam != null){
			return this.myTeam.isMyTurn(sender, timestep);
		}
		return false;
	}
	public Map<AbstractChannel, List<NAITOMessage>> 
	mapChannelToMessages(List<NAITOMessage> messages){
		Map<AbstractChannel, List<NAITOMessage>> result
			= new HashMap<AbstractChannel, List<NAITOMessage>>();
		for(NAITOMessage message : messages){
			MessageType type = message.getType();
			List<AbstractChannel> channels;
			switch(type){
			case FIRE:
				channels = getChannelToFB();
				break;
			case BLOCKED:
				channels = getChannelToPF();
				break;
			case CIVILIAN:
				channels = getChannelToAT();
				break;
			case HELP_BLOCK:
				channels = getChannelToPF();
				break;
			case HELP_BUILDING:
				channels = getChannelToAT();
			default:
				//
				channels = new ArrayList<AbstractChannel>();
			}
			if(!channels.isEmpty()){
				// TODO どのチャネルを使うか意思決定する部分を構築する
				AbstractChannel channel = channels.get(0);
				if(result.get(channel) == null){
					result.put(channel, new ArrayList<NAITOMessage>());
				}
				result.get(channel).add(message);
			}
		}
		/* ビピンさんの実験用に... */
		/* 全てのメッセージを他のチームにも送る */
		List<AbstractChannel> toOtherTeamChannels = getChannelsToOtherTeam();
		for(AbstractChannel toOtherTeamChannel : toOtherTeamChannels){
			result.put(toOtherTeamChannel, messages);
		}
		return result;
	}
}
